package com.maple.myeventbus.core;

import android.os.Handler;
import android.os.Looper;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by maple on 2020-07-10 15:51
 * E-Mail Address：740917401@qq.com
 */
public class EventBus {
    private static volatile EventBus instance;//单例 volatile阻止重排序和保证线程间的可见性 解决DCL导致重排序问题
    private Map<Object, List<SubscribeMethod>> cacheMap;
    private Handler handler;
    private ExecutorService executorService;

    /**
     * DCL(双重检查锁定) 大幅降低synchronized带来的性能开销
     *
     * @return EventBus单例
     */
    public static EventBus getDefault() {
        if (instance == null) {
            synchronized (EventBus.class) {
                if (instance == null) {
                    instance = new EventBus();
                }
            }
        }
        return instance;
    }

    public EventBus() {
        cacheMap = new HashMap<>();
        handler = new Handler(Looper.getMainLooper());
        executorService = Executors.newCachedThreadPool();
    }

    /**
     * @param subscriber 使用注解函数的类
     */
    public void register(Object subscriber) {
        List<SubscribeMethod> subscribeMethodList = cacheMap.get(subscriber);
        if (subscribeMethodList == null) {
            subscribeMethodList = getSubscribeMethods(subscriber);
            cacheMap.put(subscriber, subscribeMethodList);
        }
    }

    /**
     * @param subscriber 使用注解函数的类
     * @return SubscribeMethod 存储信息实体类列表
     */
    private List<SubscribeMethod> getSubscribeMethods(Object subscriber) {
        List<SubscribeMethod> list = new ArrayList<>();
        Class<?> aClass = subscriber.getClass();
        while (aClass != null) {
            String name = aClass.getName();
            //排除系统类
            if (name.startsWith("java.") ||
                    name.startsWith("javax.") ||
                    name.startsWith("android.") ||
                    name.startsWith("androidx.")) {
                break;
            }
            Method[] declaredMethods = aClass.getDeclaredMethods();//获取声明的方法
            for (Method method : declaredMethods) {
                Subscribe annotation = method.getAnnotation(Subscribe.class);//获取对应的注解
                if (annotation == null) {
                    continue;
                }
                Class<?>[] parameterTypes = method.getParameterTypes();//获取对应注解的参数类型数组
                if (parameterTypes.length != 1) {
                    throw new RuntimeException("eventbus只能接收一个参数");
                }
                ThreadMode threadMode = annotation.threadMode();//线程模式
                SubscribeMethod subscribeMethod = new SubscribeMethod(method, threadMode, parameterTypes[0]);
                list.add(subscribeMethod);
            }
            aClass = aClass.getSuperclass();//获取父类 继续遍历
        }
        return list;
    }


    /**
     * 取消注册
     *
     * @param subscriber 使用注解函数的类
     */
    public void unregister(Object subscriber) {
        List<SubscribeMethod> subscribeMethodList = cacheMap.get(subscriber);
        if (subscribeMethodList != null) {
            cacheMap.remove(subscriber);
        }
    }


    /**
     * 事件传递
     *
     * @param args 事件类型
     */
    public void post(final Object args) {
        Set<Object> set = cacheMap.keySet();
        Iterator<Object> iterator = set.iterator();//迭代器
        while (iterator.hasNext()) {
            final Object aClass = iterator.next();//获取key：使用注解函数的类
            List<SubscribeMethod> list = cacheMap.get(aClass);
            for (final SubscribeMethod subscribeMethod : list) {
                if (subscribeMethod.getEventType().isAssignableFrom(args.getClass())) {//判断类型 父类.class.isAssignableFrom(子类.class) 子类的事件也可以传递
                    //线程切换
                    switch (subscribeMethod.getThreadMode()) {
                        case MAIN://指定在主线程执行
                            if (Looper.myLooper() == Looper.getMainLooper()) {//注解的函数在主线程 直接反射执行函数
                                invoke(subscribeMethod, aClass, args);
                            } else {//注解的函数在子线程  利用handler切换回主线程 反射执行函数
                                handler.post(() -> {
                                    invoke(subscribeMethod, aClass, args);
                                });

                            }
                            break;
                        case ASYNC://指定在子线程执行
                            if (Looper.myLooper() == Looper.getMainLooper()) {//注解的函数在主线程 利用线程池启动一个线程  反射执行函数
                                executorService.execute(() -> {
                                    invoke(subscribeMethod, aClass, args);
                                });
                            } else {//注解的函数在子线程 直接反射执行函数
                                invoke(subscribeMethod, aClass, args);
                            }
                            break;
                    }
                }
            }
        }
    }


    /**
     * 反射调用
     *
     * @param subscribeMethod 保存注解的方法的实体类
     * @param aClass          使用注解函数的类
     * @param args            注解的方法的参数
     */
    private void invoke(SubscribeMethod subscribeMethod, Object aClass, Object args) {
        Method method = subscribeMethod.getMethod();
        try {
            method.invoke(aClass, args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
